﻿using Furion.CMS.Application.Dto;
using Furion.CMS.Core;
using Furion.CMS.Core.Base;
using Furion.CMS.Core.Permission;
using Furion.CMS.Domain;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Application
{
    /// <summary>
    /// 权限应用服务
    /// </summary>
    public class PermissionAppService : BaseApplication, IScoped
    {
        private readonly IRepository<PermissionInfo> _permissionRepository;

        public PermissionAppService(IRepository<PermissionInfo> permissionRepository)
        {
            _permissionRepository = permissionRepository;
        }

        #region Configure
        /// <summary>
        /// 获取权限配置
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<List<PermissionConfigDto>> GetConfigureAsync(string key = default)
        {
            var list = await _permissionRepository
                .Where(t => t.Type == PermissionType.Menu)
                .Include(i => i.Children)
                .Where(!string.IsNullOrWhiteSpace(key), t => t.Code == key).ToListAsync();

            return list.Adapt<List<PermissionConfigDto>>();
        }

        /// <summary>
        /// 发布权限配置
        /// </summary>
        /// <param name="permissionConfigs"></param>
        [UnitOfWork]
        public void ReleaseConfigure([FromBody] List<PermissionConfigReleaseDto> permissionConfigs)
        {
            if (!permissionConfigs.Any()) throw Oops.Oh("参数错误");

            var releaseDatas = permissionConfigs.Adapt<List<PermissionInfo>>();
            var releaseDataCodes = releaseDatas.Select(s => s.Code).ToList();
            var findDic = permissionConfigs.ToDictionary(k => k.Code);

            // 缓存数据
            var dataCaches = _permissionRepository.Where(t => t.Type == PermissionType.Menu && releaseDataCodes.Contains(t.Code))
                .Include(i => i.Children)
                .ToDictionary(k => k.Code);

            // 检测配置项是新增还是添加
            // PageFunctions字段将进行平级处理
            foreach (var rd in releaseDatas)
            {
                var operateParentPaths = rd.ParentPaths.Union(new string[] { rd.Code });

                if (dataCaches.TryGetValue(rd.Code, out PermissionInfo item))
                {
                    if (!string.IsNullOrWhiteSpace(rd.Name)) item.Name = rd.Name;

                    // 对页面功能进行删除/添加操作
                    if (findDic.TryGetValue(rd.Code, out PermissionConfigReleaseDto input))
                    {
                        var menuOperates = item.Children.Where(t => t.Type == PermissionType.Operate);

                        var insertMenuOperates = new List<PermissionInfo>();
                        // 数据转换处理
                        var inputMenuOperates = input.PageFunctions.Adapt<List<PermissionInfo>>();
                        inputMenuOperates.ForEach(o =>
                        {
                            // 初始赋值
                            o.ParentPaths = operateParentPaths.ToArray();
                            o.ParentCode = rd.Code;
                            o.Type = PermissionType.Operate;

                            // 添加 or 修改
                            var update = menuOperates.FirstOrDefault(t => t.Code == o.Code);
                            if (update != null)
                            {
                                update.Name = o.Name;
                                update.ParentPaths = o.ParentPaths;
                                update.ParentCode = o.ParentCode;
                                update.DependentResources = o.DependentResources;
                            }
                            else
                            {
                                item.Children.Add(o);
                            }
                        });

                        // 删除
                        if (input.DeleteCodes.Any())
                        {
                            var deleteOperates = menuOperates.Where(t => input.DeleteCodes.Contains(t.Code));
                            _permissionRepository.Delete(deleteOperates);
                        }
                    }
                    item.ParentPaths = rd.ParentPaths;
                }
                else
                {
                    // 从父路径中找到父节点code
                    rd.ParentCode = rd.ParentPaths.LastOrDefault();
                    // 补全数据
                    foreach (var o in rd.Children)
                    {
                        o.ParentPaths = operateParentPaths.ToArray();
                        o.ParentCode = rd.Code;
                        o.Type = PermissionType.Operate;
                    }

                    _permissionRepository.InsertNow(rd);
                }
            }
        }

        /// <summary>
        /// 检查模块权限定义
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [ProducesResponseType(typeof(NotDataResult), 200)]
        [ApiDescriptionSettings(Name = "check")]
        public NotDataResult CheckModuleDefinition()
        {
            var result = new NotDataResult { Success = true };
            if (!_permissionRepository.AsQueryable(false).Any())
            {
                result.Success = false;
                result.ErrorMessage = "模块尚未初始化，您需要初始化后方可进行配置";
            }
            return result;
        }
        #endregion

        /// <summary>
        /// 获取权限项集合
        /// </summary>
        /// <returns></returns>
        public List<PermissionOptionsDto> GetOptions()
        {
            var result = _permissionRepository.Where(t => t.Type == PermissionType.Menu)
                 .Include(i => i.Children)
                 .ToList();

            return result.Where(t => string.IsNullOrWhiteSpace(t.ParentCode)).Adapt<List<PermissionOptionsDto>>();
        }

        /// <summary>
        /// 获取API资源
        /// </summary>
        /// <param name="permissionManager"></param>
        /// <returns></returns>
        public List<PermissionOptionsDto> GetResources([FromServices] IPermissionDefinitionManager permissionManager)
        {
            return permissionManager.GetGroups().Adapt<List<PermissionOptionsDto>>();
        }

        /// <summary>
        /// 获取指定权限代码分配的角色列表
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        [ApiDescriptionSettings(false)]
        public async Task<List<RoleInfo>> GetAssignRoleListAsync(string code)
        {
            var roleList = await _permissionRepository.AsQueryable(false)
                  .Where(t => t.DependentResources.Contains(code))
                  .Include(i => i.Roles)
                  .ThenInclude(i => i.Users)
                  .AsSplitQuery()
                  .SelectMany(s => s.Roles)
                  .ToListAsync();

            return roleList;
        }

        /// <summary>
        /// 获取指定权限代码分配的人员列表
        /// <para>
        /// 当权限代表被独立分配给用户时才有数据
        /// </para>
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        [ApiDescriptionSettings(false)]
        public async Task<List<UserInfo>> GetAssignUserListAsync(string code)
        {
            var userList = await _permissionRepository.AsQueryable(false)
                  .Where(t => t.DependentResources.Contains(code))
                  .Include(i => i.Users)
                  .SelectMany(s => s.Users)
                  .ToListAsync();

            return userList;
        }

        /// <summary>
        /// 获取资源分配列表
        /// </summary>
        /// <returns></returns>
        [ApiDescriptionSettings(false)]
        public async Task<List<KeyValuePair<string, IEnumerable<string>>>> GetResourceAssignListAsync()
        {
            var result = new Dictionary<string, IEnumerable<string>>();

            var permissions = await _permissionRepository.AsQueryable(false)
                .Where(t => !string.IsNullOrWhiteSpace(t.DependentResources))
                 .Include(i => i.Users)
                 .Include(i => i.Roles)
                 .ThenInclude(i => i.Users)
                 .Include(i => i.Roles)
                 .ThenInclude(i => i.Organizations)
                 .ThenInclude(i => i.Users)
                 .AsSplitQuery()
                 .ToListAsync();

            foreach (var permission in permissions)
            {
                var dependentResources = permission.DependentResources.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                // 处理角色授权
                var roleAuthorizedUserIdList = permission.Roles.SelectMany(s => s.Users, (role, user) => string.Format(CacheKeyConsts.PermissionResourceValue, role.Code, user.Id));
                // 处理关联机构授权
                var roleAuthorizedOrgUserIdList = permission.Roles.SelectMany(s => s.Organizations)
                    .SelectMany(s => s.Users, (org, user) => string.Format(CacheKeyConsts.PermissionResourceValue, org.Id, user.Id));
                // 处理独立用户授权
                var independentUserIdList = permission.Users.Select(s => string.Format(CacheKeyConsts.PermissionResourceValue, Guid.Empty, s.Id));
                foreach (var resourceId in dependentResources)
                {
                    var resourceKey = string.Format(CacheKeyConsts.PermissionResource, resourceId, "");

                    bool flag = result.TryGetValue(resourceKey, out var resourceValues);
                    resourceValues = roleAuthorizedUserIdList.Union(roleAuthorizedOrgUserIdList)
                        .Union(independentUserIdList)
                        .Union(resourceValues) // 合并已存在的集合
                        .Distinct();

                    // 集合不存在则添加
                    if (!flag)
                    {
                        result.TryAdd(resourceKey, resourceValues);
                    }
                }
            }

            return result.ToList();
        }
    }
}
